﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using CinemaLib;

namespace Administration
{
    public partial class CinemaHall : UserControl
    {
        public List<Seat> selected = new List<Seat>();
        public int SeatLimit { get; set; }
        private Hall _curhall;
        private Hall CurrentHall
        {
            get
            {
                return _curhall;
            }
            set
            {
                _curhall = value;
                this.Controls.Clear();
                AddHandlers();
            }
        }

        const int SEATSIZE = 18;

        public CinemaHall()
        {
            InitializeComponent();
        }

        public CinemaHall(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }

        public void DisposeControls()
        {
            this.Controls.Clear();
            _curhall = null;
            this.Update();
        }

        public void AddHandlers()
        {
            this.Controls.Clear();
            for (int i = 0; i < _curhall.Rows.Count; i++)
            {
                for (int j = 0; j < _curhall.Rows[i].Seats.Count; j++)
                {
                    PictureBox pb = new PictureBox();
                    
                    pb.Location = new Point(j * SEATSIZE, i * SEATSIZE);
                    pb.Size = new Size(SEATSIZE, SEATSIZE);
                    if (_curhall.Rows[i].Seats[j].Occupied)
                    {
                        pb.Image = CinemaLib.Properties.Resources.Occupied;
                        pb.Image.Tag = "Occupied";
                    }
                    else if (selected.Any(s => s.ID == _curhall.Rows[i].Seats[j].ID))
                    {
                        pb.Image = CinemaLib.Properties.Resources.Choise;
                        pb.Image.Tag = "Choise";
                    }
                    else
                    {
                        pb.Image = CinemaLib.Properties.Resources.Empty;
                        pb.Image.Tag = "Empty";
                    }
                    pb.MouseClick += new MouseEventHandler(ImageClick);
                    this.Controls.Add(pb);
                    this.Size = new Size((j + 1) * SEATSIZE, this.Size.Height);
                }
                this.Size = new Size(this.Size.Width, (i + 1) * SEATSIZE);
            }
            Update();
            (Parent.Parent as MainForm).AddTicketList();
        }

        public void Update(Hall hall)
        {
            CurrentHall = hall;
        }

        private void ImageClick(object sender, MouseEventArgs e)
        {
            PictureBox picbox = (sender as PictureBox);
            
            if (picbox.Image.Tag.ToString() == "Empty")
            {
                picbox.Image = CinemaLib.Properties.Resources.Choise;
                picbox.Image.Tag = "Choise";
                CurrentHall.Rows[picbox.Location.Y / SEATSIZE].Seats[picbox.Location.X / SEATSIZE].Occupied = true;
                selected.Add(CurrentHall.Rows[picbox.Location.Y / SEATSIZE].Seats[picbox.Location.X / SEATSIZE]);
            }
            else if (picbox.Image.Tag.ToString() == "Choise")
            {
                picbox.Image = CinemaLib.Properties.Resources.Empty;
                picbox.Image.Tag = "Empty";
                CurrentHall.Rows[picbox.Location.Y / SEATSIZE].Seats[picbox.Location.X / SEATSIZE].Occupied = false;
                selected.RemoveAll(s => s.ID == (CurrentHall.Rows[picbox.Location.Y / SEATSIZE].Seats[picbox.Location.X / SEATSIZE]).ID);
            }
            if (selected.Count > SeatLimit)
            {
                int x = CurrentHall.Rows.IndexOf(CurrentHall.Rows.First(r => r.Seats.Any(s => s.ID == selected[0].ID)));
                int y = CurrentHall.Rows[x].Seats.IndexOf(CurrentHall.Rows[x].Seats.First(s => s.ID == selected[0].ID));
                picbox = (GetChildAtPoint(new Point(y * SEATSIZE, x * SEATSIZE)) as PictureBox);
                picbox.Image = CinemaLib.Properties.Resources.Empty;
                picbox.Image.Tag = "Empty";
                CurrentHall.Rows[x].Seats[y].Occupied = false;
                selected.RemoveAt(0);
            }
            (Parent.Parent as MainForm).AddTicketList();
        }

        public void FindBestSeats(int amount)
        {
            if (CurrentHall == null)
                return;
            if (amount < selected.Count)
            {
                for (int i = 0; i < selected.Count - amount; i++)
                {
                    int x = CurrentHall.Rows.IndexOf(CurrentHall.Rows.First(r => r.Seats.Any(s => s.ID == selected[0].ID)));
                    int y = CurrentHall.Rows[x].Seats.IndexOf(CurrentHall.Rows[x].Seats.First(s => s.ID == selected[0].ID));
                    PictureBox picbox = (GetChildAtPoint(new Point(y * SEATSIZE, x * SEATSIZE)) as PictureBox);
                    picbox.Image = CinemaLib.Properties.Resources.Empty;
                    picbox.Image.Tag = "Empty";
                    CurrentHall.Rows[x].Seats[y].Occupied = false;
                    selected.RemoveAt(0);
                }
                return;
            }
            
            SeatLimit = amount;
            int Rows = CurrentHall.Rows.Count - 1;
            int Cols = CurrentHall.Rows.Max(s => s.Seats.Count) - 1;
            Point Center = new Point(Rows / 2, Cols / 2);

            List<Point> bestpoint = new List<Point>();

            for (int r = 0; r < Rows + 1; r++)
            {
                for (int c = 0; c < Cols + 1; c++)
                {
                    if (CurrentHall.Rows[r].Seats[c].Occupied)
                    {
                        continue;
                    }
                    if (bestpoint.Any(s => Distance(Center, s) >= Distance(Center, new PointF(r, c))) || bestpoint.Count == 0)
                    {
                        bestpoint.Add(new Point(r, c));
                        
                        if (bestpoint.Count > (amount - selected.Count))
                        {
                            bestpoint = bestpoint.OrderByDescending(d => Distance(d, Center)).ToList<Point>();
                            bestpoint.RemoveAt(0);
                        }
                    }
                }
            }
            foreach (Point p in bestpoint)
            {
                PictureBox pb = (GetChildAtPoint(new Point((p.Y * 18) + 1, (p.X * 18) + 1)) as PictureBox);
                pb.Image = CinemaLib.Properties.Resources.Choise;
                pb.Image.Tag = "Choise";
                CurrentHall.Rows[p.X].Seats[p.Y].Occupied = true;
                selected.Add(CurrentHall.Rows[p.X].Seats[p.Y]);
            }
            (Parent.Parent as MainForm).AddTicketList();
        }

        public static double Distance(PointF p1, PointF p2)
        {
            return Math.Sqrt(Math.Pow((p1.X - p2.X + 2) * 6, 2) + Math.Pow((p1.Y - p2.Y), 2));
        }
    }
}